classdef Tracking < Signal

properties 
	NumberOfPeriods;
	CorrelatorSpacing;
end

properties (SetAccess = protected) 
	SVID;
	State;
	IntegrationTime;
	DetectorGainFrequency = 1;
	DetectorGainCarrierPhase = 1;
	DetectorGainTime;
	PrimaryPRNCodeObjs;
	SamplesObj;
	TimeShift;
	FrequencyShift;
	CarrierPhaseShift;
	TimeShiftFilterObj;
	FrequencyShiftFilterObj;
	CarrierPhaseShiftFilterObj;
	CorrelatorOut;
	CorrelatorOutLast;
	IntegratedOld;
	Replica;
	CarrierPhase;
	FrequencyShiftStdThresholdCoarse;
	TimeShiftStdThresholdCoarse;
	FrequencyShiftStdThresholdFine;
	CarrierPhaseShiftStdThreshold;
	TimeShiftStdThresholdFine;
	FrequencyShiftFilterOut;
	CarrierPhaseShiftFilterOut;
	TimeShiftFilterOut;
end % end of properties

properties (GetAccess = protected, SetAccess = protected)
	getReplica;
	getDetectorGainTime;
	Correlate;
	getFrequencyShiftDiscriminator;
	getCarrierPhaseShiftDiscriminator;
	getTimeShiftDiscriminator;
end

methods
	
	function obj = Tracking(Name, SVID, SamplesObj, varargin)
		obj = obj@Signal(Name);
		obj.SamplesObj = SamplesObj;
		obj.SVID = SVID;
		n_pc = 0;
		for i=1:(nargin-3)
			if (isa(varargin{i}, 'PrimaryPRNCode'))
				n_pc = n_pc +1;
				obj.PrimaryPRNCodeObjs{n_pc} = varargin{i}; 
			end
		end
		obj.NumberOfPeriods = 1;
		obj.CorrelatorSpacing = 1.0;
		obj.FrequencyShiftFilterOut = 0;
		obj.TimeShiftFilterOut = 0;
		obj.CarrierPhase = 0;
		obj.CarrierPhaseShift = 0;
		obj.CarrierPhaseShiftStdThreshold = pi/6;
		switch (obj.Name)
			case 'E5'
				obj.getReplica = @obj.getReplicaE5;
				obj.getDetectorGainTime = @obj.getDetectorGainTimeE5;
				obj.Correlate = @obj.CorrelateE5;
				obj.getFrequencyShiftDiscriminator = ...
														@obj.getFrequencyShiftDiscriminatorE5;
				obj.getTimeShiftDiscriminator = @obj.getTimeShiftDiscriminatorE5;
				obj.getCarrierPhaseShiftDiscriminator = ...
														@obj.getCarrierPhaseShiftDiscriminatorE5;
				obj.CorrelatorOut = zeros(1, 12);
			case 'E5a'
				obj.getReplica = @obj.getReplicaE5a;
				obj.getDetectorGainTime = @obj.getDetectorGainTimeE5a;
				obj.Correlate = @obj.CorrelateE5a;
				obj.getFrequencyShiftDiscriminator = ...
														@obj.getFrequencyShiftDiscriminatorE5a;
				obj.getTimeShiftDiscriminator = @obj.getTimeShiftDiscriminatorE5a;
				obj.getCarrierPhaseShiftDiscriminator = ...
														@obj.getCarrierPhaseShiftDiscriminatorE5a;
				obj.CorrelatorOut = zeros(1, 6);
			case 'E5aI'
				obj.getReplica = @obj.getReplicaE5aI;
				obj.getDetectorGainTime = @obj.getDetectorGainTimeE5aI;
				obj.Correlate = @obj.CorrelateE5aI;
				obj.getFrequencyShiftDiscriminator = ...
														@obj.getFrequencyShiftDiscriminatorE5aI;
				obj.getTimeShiftDiscriminator = @obj.getTimeShiftDiscriminatorE5aI;
				obj.getCarrierPhaseShiftDiscriminator = ...
														@obj.getCarrierPhaseShiftDiscriminatorE5aI;
				obj.CorrelatorOut = zeros(1, 3);
			case 'E5aQ'
				obj.getReplica = @obj.getReplicaE5aQ;
				obj.getDetectorGainTime = @obj.getDetectorGainTimeE5aQ;
				obj.Correlate = @obj.CorrelateE5aQ;
				obj.getFrequencyShiftDiscriminator = ...
														@obj.getFrequencyShiftDiscriminatorE5aQ;
				obj.getTimeShiftDiscriminator = @obj.getTimeShiftDiscriminatorE5aQ;
				obj.getCarrierPhaseShiftDiscriminator = ...
														@obj.getCarrierPhaseShiftDiscriminatorE5aQ;
				obj.CorrelatorOut = zeros(1, 3);
			case 'E5b'
				obj.getReplica = @obj.getReplicaE5b;
				obj.getDetectorGainTime = @obj.getDetectorGainTimeE5b;
				obj.Correlate = @obj.CorrelateE5b;
				obj.getFrequencyShiftDiscriminator = ...
														@obj.getFrequencyShiftDiscriminatorE5b;
				obj.getTimeShiftDiscriminator = @obj.getTimeShiftDiscriminatorE5b;
				obj.getCarrierPhaseShiftDiscriminator = ...
														@obj.getCarrierPhaseShiftDiscriminatorE5b;
				obj.CorrelatorOut = zeros(1, 6);
			case 'E5bI'
				obj.getReplica = @obj.getReplicaE5bI;
				obj.getDetectorGainTime = @obj.getDetectorGainTimeE5bI;
				obj.Correlate = @obj.CorrelateE5bI;
				obj.getFrequencyShiftDiscriminator = ...
														@obj.getFrequencyShiftDiscriminatorE5bI;
				obj.getTimeShiftDiscriminator = @obj.getTimeShiftDiscriminatorE5bI;
				obj.getCarrierPhaseShiftDiscriminator = ...
														@obj.getCarrierPhaseShiftDiscriminatorE5bI;
				obj.CorrelatorOut = zeros(1, 3);
			case 'E5bQ'
				obj.getReplica = @obj.getReplicaE5bQ;
				obj.getDetectorGainTime = @obj.getDetectorGainTimeE5bQ;
				obj.Correlate = @obj.CorrelateE5bQ;
				obj.getFrequencyShiftDiscriminator = ...
														@obj.getFrequencyShiftDiscriminatorE5bQ;
				obj.getTimeShiftDiscriminator = @obj.getTimeShiftDiscriminatorE5bQ;
				obj.getCarrierPhaseShiftDiscriminator = ...
														@obj.getCarrierPhaseShiftDiscriminatorE5bQ;
				obj.CorrelatorOut = zeros(1, 3);
			case 'E1'
				obj.CorrelatorSpacing = 0.5;
				obj.getReplica = @obj.getReplicaE1;
				obj.getDetectorGainTime = @obj.getDetectorGainTimeE1;
				obj.Correlate = @obj.CorrelateE1;
				obj.getFrequencyShiftDiscriminator = ...
														@obj.getFrequencyShiftDiscriminatorE1;
				obj.getTimeShiftDiscriminator = @obj.getTimeShiftDiscriminatorE1;
				obj.getCarrierPhaseShiftDiscriminator = ...
														@obj.getCarrierPhaseShiftDiscriminatorE1;
				obj.CorrelatorOut = zeros(1, 6);
			case 'E1b'
				obj.CorrelatorSpacing = 0.5;
				obj.getReplica = @obj.getReplicaE1b;
				obj.getDetectorGainTime = @obj.getDetectorGainTimeE1b;
				obj.Correlate = @obj.CorrelateE1b;
				obj.getFrequencyShiftDiscriminator = ...
														@obj.getFrequencyShiftDiscriminatorE1b;
				obj.getTimeShiftDiscriminator = @obj.getTimeShiftDiscriminatorE1b;
				obj.getCarrierPhaseShiftDiscriminator = ...
														@obj.getCarrierPhaseShiftDiscriminatorE1b;
				obj.CorrelatorOut = zeros(1, 3);
			case 'E1c'
				obj.CorrelatorSpacing = 0.5;
				obj.getReplica = @obj.getReplicaE1c;
				obj.getDetectorGainTime = @obj.getDetectorGainTimeE1c;
				obj.Correlate = @obj.CorrelateE1c;
				obj.getFrequencyShiftDiscriminator = ...
														@obj.getFrequencyShiftDiscriminatorE1c;
				obj.getTimeShiftDiscriminator = @obj.getTimeShiftDiscriminatorE1c;
				obj.getCarrierPhaseShiftDiscriminator = ...
														@obj.getCarrierPhaseShiftDiscriminatorE1c;
				obj.CorrelatorOut = zeros(1, 3);
			case 'B1'
				obj.getReplica = @obj.getReplicaB1;
				obj.getDetectorGainTime = @obj.getDetectorGainTimeB1;
				obj.Correlate = @obj.CorrelateB1;
				obj.getFrequencyShiftDiscriminator = ...
														@obj.getFrequencyShiftDiscriminatorB1;
				obj.getTimeShiftDiscriminator = @obj.getTimeShiftDiscriminatorB1;
				obj.getCarrierPhaseShiftDiscriminator = ...
														@obj.getCarrierPhaseShiftDiscriminatorB1;
				obj.CorrelatorOut = zeros(1, 3);
			otherwise
				error('Unknown signal')
		end
		obj.getDetectorGainTime();
	end

	function obj = setFrequencyShiftFilter(obj, LoopOrder, Bandwidth)
		if (isempty(obj.FrequencyShiftFilterObj))
			obj.FrequencyShiftFilterObj = FrequencyShiftFilter(obj.Name,...
				LoopOrder, Bandwidth, obj.DetectorGainFrequency, obj.IntegrationTime);
		else
			obj.FrequencyShiftFilterObj.LoopOrder = LoopOrder;
			obj.FrequencyShiftFilterObj.Bandwidth = Bandwidth;
			obj.FrequencyShiftFilterObj.DetectorGain = obj.DetectorGainFrequency;
			obj.FrequencyShiftFilterObj.IntegrationTime = obj.IntegrationTime;
			obj.FrequencyShiftFilterObj.refresh();
		end
	end

	function obj = setTimeShiftFilter(obj, LoopOrder, Bandwidth)
		if (isempty(obj.TimeShiftFilterObj))
			obj.TimeShiftFilterObj = TimeShiftFilter(obj.Name,...
				LoopOrder, Bandwidth, obj.DetectorGainTime, obj.IntegrationTime);
		else
			obj.TimeShiftFilterObj.LoopOrder = LoopOrder;
			obj.TimeShiftFilterObj.Bandwidth = Bandwidth;
			obj.TimeShiftFilterObj.DetectorGain = obj.DetectorGainTime;
			obj.TimeShiftFilterObj.IntegrationTime = obj.IntegrationTime;
			obj.TimeShiftFilterObj.refresh();
		end
	end

	function obj = setCarrierPhaseShiftFilter(obj, LoopOrder, Bandwidth)
		if (isempty(obj.CarrierPhaseShiftFilterObj))
			obj.CarrierPhaseShiftFilterObj = CarrierPhaseShiftFilter(obj.Name,...
				LoopOrder, Bandwidth, obj.DetectorGainCarrierPhase,obj.IntegrationTime);
		else
			obj.CarrierPhaseShiftFilterObj.LoopOrder = LoopOrder;
			obj.CarrierPhaseShiftFilterObj.Bandwidth = Bandwidth;
			obj.CarrierPhaseShiftFilterObj.DetectorGain = ...
																									obj.DetectorGainCarrierPhase;
			obj.CarrierPhaseShiftFilterObj.IntegrationTime = obj.IntegrationTime;
			obj.CarrierPhaseShiftFilterObj.refresh();
		end
	end


	function obj = resetFrequencyShiftFilter(obj, LoopOrder, Bandwidth)
		obj.setFrequencyShiftFilter(LoopOrder, Bandwidth);
		obj.FrequencyShiftFilterObj.reset();
	end

	function obj = resetTimeShiftFilter(obj, LoopOrder, Bandwidth)
		obj.setTimeShiftFilter(LoopOrder, Bandwidth);
		obj.TimeShiftFilterObj.reset();
	end

	function obj = resetCarrierPhaseShiftFilter(obj, LoopOrder, Bandwidth)
		obj.setCarrierPhaseShiftFilter(LoopOrder, Bandwidth);
		obj.CarrierPhaseShiftFilterObj.reset();
	end

	function obj = initState(obj, TimeShift, FrequencyShift)
		obj.TimeShift = TimeShift; 
		obj.FrequencyShift = FrequencyShift;
		obj.CarrierPhase = -2*pi*obj.FrequencyShift*obj.SamplesObj.SamplingPeriod;
		obj.State = 'Coarse';
	end

	function obj = setState(obj, newState)
		obj.State = newState;
	end

	function out = getFrequencyShiftStdThreshold(obj)
		switch (obj.State)
			case 'Acq'
				error('In Acq state no tracking thresholds are available')
			case 'Coarse'
				out = obj.FrequencyShiftStdThresholdCoarse;
			case 'Fine'
				out = obj.FrequencyShiftStdThresholdFine;
			otherwise
				error('Unknown tracking state')
		end
	end

	function out = getTimeShiftStdThreshold(obj)
		switch (obj.State)
			case 'Acq'
				error('In Acq state no tracking thresholds are available')
			case 'Coarse'
				out = obj.TimeShiftStdThresholdCoarse;
			case 'Fine'
				out = obj.TimeShiftStdThresholdFine;
			otherwise
				error('Unknown tracking state')
		end
	end

	function obj = Track(obj, varargin)
		if (nargin > 1)
			SecondaryCode = varargin;
		end

		if (~isempty(obj.CorrelatorOutLast))
			obj.CorrelatorOutLast = obj.CorrelatorOut;
		end

		[m n] = size(obj.CorrelatorOut);
		obj.CorrelatorOut = zeros(m, n);
		for i=1:obj.NumberOfPeriods
			if (nargin > 1)
				obj.Correlate(SecondaryCode(i))
			else
				obj.Correlate();
			end
			obj.updateFrequencyShiftNCO();
			obj.updateTimeShiftNCO();
		end

		if (isempty(obj.CorrelatorOutLast))
			obj.CorrelatorOutLast = obj.CorrelatorOut;
		end

		obj.filterFrequencyShift(obj.getFrequencyShiftDiscriminator());
		obj.filterTimeShift(obj.getTimeShiftDiscriminator(), obj.FrequencyShift-...
												obj.SamplesObj.FrequencyOffset);
		if (strcmp(obj.State,'Fine'))
			obj.filterCarrierPhaseShift(obj.getCarrierPhaseShiftDiscriminator());
		end
	end

	function obj = set.NumberOfPeriods(obj, val)
		obj.NumberOfPeriods = val;
		obj.IntegrationTime = obj.PrimaryPRNCodeObjs{1}.ChipPeriod *...
													obj.PrimaryPRNCodeObjs{1}.NumberOfChips *...
	 												obj.NumberOfPeriods;
		obj.FrequencyShiftStdThresholdCoarse = 1/(12 * obj.IntegrationTime);
		obj.FrequencyShiftStdThresholdFine = ...
																			obj.FrequencyShiftStdThresholdCoarse/10;
	end

	function obj = set.CorrelatorSpacing(obj, val)
		obj.CorrelatorSpacing = val;
		obj.TimeShiftStdThresholdCoarse = 1/6 * obj.CorrelatorSpacing * ...
																			obj.PrimaryPRNCodeObjs{1}.ChipPeriod;
		obj.TimeShiftStdThresholdFine = obj.TimeShiftStdThresholdCoarse/2;
	end

end % end of methods

methods (Access = protected)

	function obj = CorrelateE5(obj, varargin)
		obj = obj.CorrelateE5a(varargin{:});
	end

	function obj = CorrelateE5a(obj, varargin)
		if (nargin > 1)
			sc = varargin{1};
		else
			sc = 1;
		end
		obj.getReplica();
		
		if (isempty(obj.IntegratedOld))
			[m n] = size(obj.CorrelatorOut);
			obj.IntegratedOld = zeros(m, n);
		end

		obj.SamplesObj.loadSamples(...
												obj.PrimaryPRNCodeObjs{1}.NumberOfUpsampledSamples);

		Tp = obj.PrimaryPRNCodeObjs{1}.UpsampledCodesPeriod;
		N = obj.PrimaryPRNCodeObjs{1}.NumberOfUpsampledSamples;
		ind = floor(mod(obj.TimeShift/Tp, N));
		if (ind < 0)
			ind = ind + N;
		end
		ind = ind +1;
		
		IntegratedNew = obj.SamplesObj.Data(1:ind).' *...
	 									conj(obj.Replica((1:ind),:));
		obj.CorrelatorOut = (obj.IntegratedOld + IntegratedNew)*sc; 
		IntegratedNew = obj.SamplesObj.Data((ind+1):end).' *...
										conj(obj.Replica(((ind+1):end), :));
		obj.IntegratedOld = IntegratedNew;

	end

	function obj = CorrelateE5aI(obj, varargin)
		obj = obj.CorrelateE5a(varargin{:});
	end

	function obj = CorrelateE5aQ(obj, varargin)
		obj = obj.CorrelateE5a(varargin{:});
	end

	function obj = CorrelateE5b(obj, varargin)
		obj = obj.CorrelateE5a(varargin{:});
	end

	function obj = CorrelateE5bI(obj, varargin)
		obj = obj.CorrelateE5a(varargin{:});
	end

	function obj = CorrelateE5bQ(obj, varargin)
		obj = obj.CorrelateE5a(varargin{:});
	end

	function obj = CorrelateE1(obj, varargin)
		obj = obj.CorrelateE5a(varargin{:});
	end

	function obj = CorrelateE1b(obj, varargin)
		obj = obj.CorrelateE5a(varargin{:});
	end

	function obj = CorrelateE1c(obj, varargin)
		obj = obj.CorrelateE5a(varargin{:});
	end

	function obj = CorrelateB1(obj, varargin)
		obj = obj.CorrelateE5a(varargin{:});
	end

	function out = getFrequencyShiftDiscriminatorE5(obj)
	end

	function out = getFrequencyShiftDiscriminatorE5a(obj)
		ZP_new = obj.CorrelatorOut(2);
		ZP_old = obj.CorrelatorOutLast(2);
		T = obj.IntegrationTime;
		I_PS1 = real(ZP_old); Q_PS1 = imag(ZP_old); 
		I_PS2 = real(ZP_new); Q_PS2 = imag(ZP_new); 
		dot = I_PS1.*I_PS2 + Q_PS1.*Q_PS2;
		cross = I_PS1.*Q_PS2 - I_PS2.*Q_PS1;
		out1 = 1/(2*pi*T) * atan(cross/dot);

		ZP_new = obj.CorrelatorOut(5);
		ZP_old = obj.CorrelatorOutLast(5);
		I_PS1 = real(ZP_old); Q_PS1 = imag(ZP_old); 
		I_PS2 = real(ZP_new); Q_PS2 = imag(ZP_new); 
		dot = I_PS1.*I_PS2 + Q_PS1.*Q_PS2;
		cross = I_PS1.*Q_PS2 - I_PS2.*Q_PS1;
		out2 = 1/(2*pi*T) * atan(cross/dot);

		out = (out1 + out2)/2;
	end

	function out = getFrequencyShiftDiscriminatorE5aI(obj)
		ZP_new = obj.CorrelatorOut(2);
		ZP_old = obj.CorrelatorOutLast(2);
		T = obj.IntegrationTime;
		I_PS1 = real(ZP_old); Q_PS1 = imag(ZP_old); 
		I_PS2 = real(ZP_new); Q_PS2 = imag(ZP_new); 
		dot = I_PS1.*I_PS2 + Q_PS1.*Q_PS2;
		cross = I_PS1.*Q_PS2 - I_PS2.*Q_PS1;
		out = 1/(2*pi*T) * atan(cross/dot);
	end

	function out = getFrequencyShiftDiscriminatorE5aQ(obj)
		out = obj.getFrequencyShiftDiscriminatorE5aI();
	end

	function out = getFrequencyShiftDiscriminatorE5b(obj)
		out = obj.getFrequencyShiftDiscriminatorE5a();
	end

	function out = getFrequencyShiftDiscriminatorE5bI(obj)
		out = obj.getFrequencyShiftDiscriminatorE5aI();
	end

	function out = getFrequencyShiftDiscriminatorE5bQ(obj)
		out = obj.getFrequencyShiftDiscriminatorE5aI();
	end

	function out = getFrequencyShiftDiscriminatorE1(obj)
		out = obj.getFrequencyShiftDiscriminatorE5a();
	end

	function out = getFrequencyShiftDiscriminatorE1b(obj)
		out = obj.getFrequencyShiftDiscriminatorE5aI();
	end

	function out = getFrequencyShiftDiscriminatorE1c(obj)
		out = obj.getFrequencyShiftDiscriminatorE5aI();
	end

	function out = getFrequencyShiftDiscriminatorB1(obj)
		out = obj.getFrequencyShiftDiscriminatorE5aI();
	end

	function out = getCarrierPhaseShiftDiscriminatorE5(obj)
	end

	function out = getCarrierPhaseShiftDiscriminatorE5a(obj)
		ZI = obj.CorrelatorOut(2);
		ZQ = obj.CorrelatorOut(2);
		outI = atan(imag(ZI)/real(ZI));
		outQ = atan(imag(ZQ)/real(ZQ));
		out = (outI + outQ)/2;
	end
	
	function out = getCarrierPhaseShiftDiscriminatorE5aI(obj)
		ZI = obj.CorrelatorOut(2);
		out = atan(imag(ZI)/real(ZI));
	end
	
	function out = getCarrierPhaseShiftDiscriminatorE5aQ(obj)
		out = obj.getCarrierPhaseShiftDiscriminatorE5aI();
	end

	function out = getCarrierPhaseShiftDiscriminatorE5b(obj)
		out = obj.getCarrierPhaseShiftDiscriminatorE5a();
	end

	function out = getCarrierPhaseShiftDiscriminatorE5bI(obj)
		out = obj.getCarrierPhaseShiftDiscriminatorE5aI();
	end

	function out = getCarrierPhaseShiftDiscriminatorE5bQ(obj)
		out = obj.getCarrierPhaseShiftDiscriminatorE5aI();
	end

	function out = getCarrierPhaseShiftDiscriminatorE1(obj)
		out = obj.getCarrierPhaseShiftDiscriminatorE5a();
	end

	function out = getCarrierPhaseShiftDiscriminatorE1b(obj)
		out = obj.getCarrierPhaseShiftDiscriminatorE5aI();
	end

	function out = getCarrierPhaseShiftDiscriminatorE1c(obj)
		out = obj.getCarrierPhaseShiftDiscriminatorE5aI();
	end

	function out = getCarrierPhaseShiftDiscriminatorB1(obj)
		out = obj.getCarrierPhaseShiftDiscriminatorE5aI();
	end

	function obj = filterFrequencyShift(obj, DiscriminatorOut)
		obj.FrequencyShiftFilterOut = ...
													obj.FrequencyShiftFilterObj.filter(DiscriminatorOut);
	end

	function obj = filterCarrierPhaseShift(obj, DiscriminatorOut)
		obj.CarrierPhaseShiftFilterOut = ...
											obj.CarrierPhaseShiftFilterObj.filter(DiscriminatorOut);
	end

	function obj = updateFrequencyShiftNCO(obj)
		obj.FrequencyShift = obj.FrequencyShift + obj.FrequencyShiftFilterOut;
		if (strcmp(obj.State, 'Fine') && (~isempty(obj.CarrierPhaseShiftFilterOut)))
			obj.CarrierPhaseShift = obj.CarrierPhaseShift +...
		 													obj.CarrierPhaseShiftFilterOut;
		end
	end

	function out = getTimeShiftDiscriminatorE5(obj)
	end

	function out = getTimeShiftDiscriminatorE5a(obj)
		ZE = obj.CorrelatorOut(1);
		ZL = obj.CorrelatorOut(3);
		out1 = (abs(ZE)^2 - abs(ZL)^2)/(abs(ZE)^2 + abs(ZL)^2);

		ZE = obj.CorrelatorOut(4);
		ZL = obj.CorrelatorOut(6);
		out2 = (abs(ZE)^2 - abs(ZL)^2)/(abs(ZE)^2 + abs(ZL)^2);
		
		out = (out1 + out2)/2;
	end

	function out = getTimeShiftDiscriminatorE5aI(obj)
		ZE = obj.CorrelatorOut(1);
		ZL = obj.CorrelatorOut(3);
		out = (abs(ZE)^2 - abs(ZL)^2)/(abs(ZE)^2 + abs(ZL)^2);
	end

	function out = getTimeShiftDiscriminatorE5aQ(obj)
		out = obj.getTimeShiftDiscriminatorE5aI();
	end

	function out = getTimeShiftDiscriminatorE5b(obj)
		out = obj.getTimeShiftDiscriminatorE5a();
	end

	function out = getTimeShiftDiscriminatorE5bI(obj)
		out = obj.getTimeShiftDiscriminatorE5aI();
	end

	function out = getTimeShiftDiscriminatorE5bQ(obj)
		out = obj.getTimeShiftDiscriminatorE5aI();
	end

	function out = getTimeShiftDiscriminatorE1(obj)
		out = obj.getTimeShiftDiscriminatorE5a();
		%out = obj.getTimeShiftDiscriminatorE5aI();
	end

	function out = getTimeShiftDiscriminatorE1b(obj)
		out = obj.getTimeShiftDiscriminatorE5aI();
	end

	function out = getTimeShiftDiscriminatorE1c(obj)
		out = obj.getTimeShiftDiscriminatorE5aI();
	end

	function out = getTimeShiftDiscriminatorB1(obj)
		out = obj.getTimeShiftDiscriminatorE5aI();
	end

	function obj = filterTimeShift(obj, DiscriminatorOut, FrequencyShift)
		obj.TimeShiftFilterOut = ...
					obj.TimeShiftFilterObj.filter(DiscriminatorOut, FrequencyShift);
	end

	function obj = updateTimeShiftNCO(obj)
		NcTc = obj.PrimaryPRNCodeObjs{1}.ChipPeriod * ...
					 obj.PrimaryPRNCodeObjs{1}.NumberOfChips;
		obj.TimeShift = mod(obj.TimeShift - obj.TimeShiftFilterOut +...
										obj.IntegrationTime/NcTc, NcTc);
	end

	function obj = getReplicaE5(obj)
	end

	function obj = getReplicaE5a(obj)
		N = obj.PrimaryPRNCodeObjs{1}.NumberOfUpsampledSamples;
		Tp = obj.SamplesObj.SamplingPeriod;
		Dtaus = obj.CorrelatorSpacing * obj.PrimaryPRNCodeObjs{1}.ChipPeriod / 2;
		fs = obj.FrequencyShift;
		phi = obj.CarrierPhase;
		%obj.CarrierPhaseShift
		phi = phi + obj.CarrierPhaseShift;
		code_ai_e=obj.PrimaryPRNCodeObjs{1}.getCode(obj.SVID, obj.TimeShift-Dtaus);
		code_ai=obj.PrimaryPRNCodeObjs{1}.getCode(obj.SVID, obj.TimeShift);
		code_ai_l=obj.PrimaryPRNCodeObjs{1}.getCode(obj.SVID, obj.TimeShift+Dtaus);
		code_aq_e=obj.PrimaryPRNCodeObjs{2}.getCode(obj.SVID, obj.TimeShift-Dtaus);
		code_aq=obj.PrimaryPRNCodeObjs{2}.getCode(obj.SVID, obj.TimeShift);
		code_aq_l=obj.PrimaryPRNCodeObjs{2}.getCode(obj.SVID, obj.TimeShift+Dtaus);
		carr = exp(j*(2*pi*fs*(1:N)*Tp + phi));
		obj.CarrierPhase = angle(carr(end));
		obj.Replica(:,1) = ((  (-2*code_ai_e +1)) .* carr).';
		obj.Replica(:,2) = ((  (-2*code_ai   +1))	.* carr).';
		obj.Replica(:,3) = ((  (-2*code_ai_l +1)) .* carr).';
		obj.Replica(:,4) = ((j*(-2*code_aq_e +1)) .* carr).';
		obj.Replica(:,5) = ((j*(-2*code_aq   +1))	.* carr).';
		obj.Replica(:,6) = ((j*(-2*code_aq_l +1)) .* carr).';
	end

	function obj = getReplicaE5aI(obj)
		N = obj.PrimaryPRNCodeObjs{1}.NumberOfUpsampledSamples;
		Tp = obj.SamplesObj.SamplingPeriod;
		Dtaus = obj.CorrelatorSpacing * obj.PrimaryPRNCodeObjs{1}.ChipPeriod / 2;
		fs = obj.FrequencyShift;
		phi = obj.CarrierPhase;
		phi = phi + obj.CarrierPhaseShift;
		code_ai_e=obj.PrimaryPRNCodeObjs{1}.getCode(obj.SVID, obj.TimeShift-Dtaus);
		code_ai=obj.PrimaryPRNCodeObjs{1}.getCode(obj.SVID, obj.TimeShift);
		code_ai_l=obj.PrimaryPRNCodeObjs{1}.getCode(obj.SVID, obj.TimeShift+Dtaus);
		carr = exp(j*(2*pi*fs*(1:N)*Tp + phi));
		obj.CarrierPhase = angle(carr(end));
		obj.Replica(:,1) = ((  (-2*code_ai_e +1)) .* carr).';
		obj.Replica(:,2) = ((  (-2*code_ai   +1))	.* carr).';
		obj.Replica(:,3) = ((  (-2*code_ai_l +1)) .* carr).';
	end

	function obj = getReplicaE5aQ(obj)
		obj = obj.getReplicaE5aI();
		obj.Replica = j*obj.Replica;
	end

	function obj = getReplicaE5b(obj)
		obj = obj.getReplicaE5a();
	end

	function obj = getReplicaE5bI(obj)
		obj = obj.getReplicaE5aI();
	end

	function obj = getReplicaE5bQ(obj)
		obj = obj.getReplicaE5aQ();
	end

	function obj = getReplicaE1(obj)
		N = obj.PrimaryPRNCodeObjs{1}.NumberOfUpsampledSamples;
		Tp = obj.SamplesObj.SamplingPeriod;
		Dtaus = obj.CorrelatorSpacing * obj.PrimaryPRNCodeObjs{1}.ChipPeriod / 2;
		fs = obj.FrequencyShift;
		phi = obj.CarrierPhase;
		phi = phi + obj.CarrierPhaseShift;
		code_b_e=obj.PrimaryPRNCodeObjs{1}.getCode(obj.SVID, obj.TimeShift-Dtaus);
		code_b=obj.PrimaryPRNCodeObjs{1}.getCode(obj.SVID, obj.TimeShift);
		code_b_l=obj.PrimaryPRNCodeObjs{1}.getCode(obj.SVID, obj.TimeShift+Dtaus);
		code_c_e=obj.PrimaryPRNCodeObjs{2}.getCode(obj.SVID, obj.TimeShift-Dtaus);
		code_c=obj.PrimaryPRNCodeObjs{2}.getCode(obj.SVID, obj.TimeShift);
		code_c_l=obj.PrimaryPRNCodeObjs{2}.getCode(obj.SVID, obj.TimeShift+Dtaus);
		Rs = 1/obj.PrimaryPRNCodeObjs{1}.ChipPeriod;
		sc_vec_e = sign(sin(2*pi*Rs*((1:N)*Tp -Dtaus)));
		sc_vec_p = sign(sin(2*pi*Rs*((1:N)*Tp 			)));
		sc_vec_l = sign(sin(2*pi*Rs*((1:N)*Tp +Dtaus)));
		carr = exp(j*(2*pi*fs*(1:N)*Tp + phi));
		obj.CarrierPhase = angle(carr(end));
		carrsc_e = carr.*sc_vec_e;
		carrsc_p = carr.*sc_vec_p;
		carrsc_l = carr.*sc_vec_l;
		obj.Replica(:,1) = ((  (-2*code_b_e +1))  .* carrsc_e).';
		obj.Replica(:,2) = ((  (-2*code_b   +1))	.* carrsc_p).';
		obj.Replica(:,3) = ((  (-2*code_b_l +1))  .* carrsc_l).';
		obj.Replica(:,4) = (( -(-2*code_c_e +1))  .* carrsc_e).';
		obj.Replica(:,5) = (( -(-2*code_c   +1))	.* carrsc_p).';
		obj.Replica(:,6) = (( -(-2*code_c_l +1))  .* carrsc_l).';
	end

	function obj = getReplicaE1b(obj)
		N = obj.PrimaryPRNCodeObjs{1}.NumberOfUpsampledSamples;
		Tp = obj.SamplesObj.SamplingPeriod;
		Dtaus = obj.CorrelatorSpacing * obj.PrimaryPRNCodeObjs{1}.ChipPeriod / 2;
		fs = obj.FrequencyShift;
		phi = obj.CarrierPhase;
		phi = phi + obj.CarrierPhaseShift;
		code_b_e=obj.PrimaryPRNCodeObjs{1}.getCode(obj.SVID, obj.TimeShift-Dtaus);
		code_b=obj.PrimaryPRNCodeObjs{1}.getCode(obj.SVID, obj.TimeShift);
		code_b_l=obj.PrimaryPRNCodeObjs{1}.getCode(obj.SVID, obj.TimeShift+Dtaus);
		Rs = 1/obj.PrimaryPRNCodeObjs{1}.ChipPeriod;
		sc_vec = sign(sin(2*pi*Rs*(1:N)*Tp));
		carr = exp(j*(2*pi*fs*(1:N)*Tp + phi));
		obj.CarrierPhase = angle(carr(end));
		carrsc = carr.*sc_vec;
		obj.Replica(:,1) = ((  (-2*code_b_e +1))  .* carrsc).';
		obj.Replica(:,2) = ((  (-2*code_b   +1))	.* carrsc).';
		obj.Replica(:,3) = ((  (-2*code_b_l +1))  .* carrsc).';
	end

	function obj = getReplicaE1c(obj)
		obj = obj.getReplicaE1b();
		obj.Replica = - obj.Replica;
	end

	function obj = getReplicaB1(obj)
		obj = obj.getReplicaE5aI();
	end

	function obj = getDetectorGainTimeE5(obj)
	end

	function obj = getDetectorGainTimeE5a(obj)
		Tc = obj.PrimaryPRNCodeObjs{1}.ChipPeriod;
		Dtaus = Tc * obj.CorrelatorSpacing/2;
		obj.DetectorGainTime = (2*Tc - Dtaus)/((Tc - Dtaus)^2);
	end

	function obj = getDetectorGainTimeE5aI(obj)
		obj = obj.getDetectorGainTimeE5a();
	end

	function obj = getDetectorGainTimeE5aQ(obj)
		obj = obj.getDetectorGainTimeE5a();
	end

	function obj = getDetectorGainTimeE5b(obj)
		obj = obj.getDetectorGainTimeE5a();
	end

	function obj = getDetectorGainTimeE5bI(obj)
		obj = obj.getDetectorGainTimeE5a();
	end

	function obj = getDetectorGainTimeE5bQ(obj)
		obj = obj.getDetectorGainTimeE5a();
	end

	function obj = getDetectorGainTimeE1(obj)
		Tc = obj.PrimaryPRNCodeObjs{1}.ChipPeriod;
		Tr = Tc/2;
		Dtaus = Tc * obj.CorrelatorSpacing/2;
		obj.DetectorGainTime = (2*Tr - Dtaus)/((Tr - Dtaus)^2);
	end

	function obj = getDetectorGainTimeE1b(obj)
		obj = obj.getDetectorGainTimeE5a();
	end

	function obj = getDetectorGainTimeE1c(obj)
		obj = obj.getDetectorGainTimeE5a();
	end

	function obj = getDetectorGainTimeB1(obj)
		obj = obj.getDetectorGainTimeE5a();
	end

end

end % end of class  
